﻿namespace Community.CsharpSqlite.Entity
{
    /*
    ** A open page cache is an instance of the following structure.
    **
    ** errCode
    **
    **   Pager.errCode may be set to StatusCode.SQLITE_IOERR, StatusCode.SQLITE_CORRUPT, or
    **   or StatusCode.SQLITE_FULL. Once one of the first three errors occurs, it persists
    **   and is returned as the result of every major pager API call.  The
    **   StatusCode.SQLITE_FULL return code is slightly different. It persists only until the
    **   next successful rollback is performed on the pager cache. Also,
    **   StatusCode.SQLITE_FULL does not affect the sqlite3PagerGet() and sqlite3PagerLookup()
    **   APIs, they may still be used successfully.
    **
    ** dbSizeValid, dbSize, dbOrigSize, dbFileSize
    **
    **   Managing the size of the database file in pages is a little complicated.
    **   The variable Pager.dbSize contains the number of pages that the database
    **   image currently contains. As the database image grows or shrinks this
    **   variable is updated. The variable Pager.dbFileSize contains the number
    **   of pages in the database file. This may be different from Pager.dbSize
    **   if some pages have been appended to the database image but not yet written
    **   out from the cache to the actual file on disk. Or if the image has been
    **   truncated by an incremental-vacuum operation. The Pager.dbOrigSize variable
    **   contains the number of pages in the database image when the current
    **   transaction was opened. The contents of all three of these variables is
    **   only guaranteed to be correct if the boolean Pager.dbSizeValid is true.
    **
    **   TODO: Under what conditions is dbSizeValid set? Cleared?
    **
    ** changeCountDone
    **
    **   This boolean variable is used to make sure that the change-counter
    **   (the 4-byte header field at byte offset 24 of the database file) is
    **   not updated more often than necessary.
    **
    **   It is set to true when the change-counter field is updated, which
    **   can only happen if an exclusive lock is held on the database file.
    **   It is cleared (set to false) whenever an exclusive lock is
    **   relinquished on the database file. Each time a transaction is committed,
    **   The changeCountDone flag is inspected. If it is true, the work of
    **   updating the change-counter is omitted for the current transaction.
    **
    **   This mechanism means that when running in exclusive mode, a connection
    **   need only update the change-counter once, for the first transaction
    **   committed.
    **
    ** dbModified
    **
    **   The dbModified flag is set whenever a database page is dirtied.
    **   It is cleared at the end of each transaction.
    **
    **   It is used when committing or otherwise ending a transaction. If
    **   the dbModified flag is clear then less work has to be done.
    **
    ** journalStarted
    **
    **   This flag is set whenever the the main journal is synced.
    **
    **   The point of this flag is that it must be set after the
    **   first journal header in a journal file has been synced to disk.
    **   After this has happened, new pages appended to the database
    **   do not need the PGHDR_NEED_SYNC flag set, as they do not need
    **   to wait for a journal sync before they can be written out to
    **   the database file (see function pager_write()).
    **
    ** setMaster
    **
    **   This variable is used to ensure that the master journal file name
    **   (if any) is only written into the journal file once.
    **
    **   When committing a transaction, the master journal file name (if any)
    **   may be written into the journal file while the pager is still in
    **   PAGER_RESERVED state (see CommitPhaseOne() for the action). It
    **   then attempts to upgrade to an exclusive lock. If this attempt
    **   fails, then StatusCode.SQLITE_BUSY may be returned to the user and the user
    **   may attempt to commit the transaction again later (calling
    **   CommitPhaseOne() again). This flag is used to ensure that the
    **   master journal name is only written to the journal file the first
    **   time CommitPhaseOne() is called.
    **
    ** doNotSync
    **
    **   This variable is set and cleared by PagerHelper.PagerWrite().
    **
    ** needSync
    **
    **   TODO: It might be easier to set this variable in writeJournalHdr()
    **   and writeMasterJournal() only. Change its meaning to "unsynced data
    **   has been written to the journal".
    **
    ** subjInMemory
    **
    **   This is a boolean variable. If true, then any required sub-journal
    **   is opened as an in-memory journal file. If false, then in-memory
    **   sub-journals are only used for in-memory pager files.
    */

    public class Pager
    {
        public sqlite3_vfs pVfs; /* OS functions to use for IO */
        public bool exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
        public byte journalMode; /* On of the PAGER_JOURNALMODE_* values */
        public byte useJournal; /* Use a rollback journal on this file */
        public byte noReadlock; /* Do not bother to obtain readlocks */
        public bool noSync; /* Do not sync the journal if true */
        public bool fullSync; /* Do extra syncs of the journal for robustness */
        public int sync_flags; /* One of SYNC_NORMAL or SYNC_FULL */
        public bool tempFile; /* zFilename is a temporary file */
        public bool readOnly; /* True for a read-only database */
        public bool alwaysRollback; /* Disable DontRollback() for all pages */
        public byte memDb; /* True to inhibit all file I/O */
        /* The following block contains those class members that are dynamically
        ** modified during normal operations. The other variables in this structure
        ** are either constant throughout the lifetime of the pager, or else
        ** used to store configuration parameters that affect the way the pager
        ** operates.
        **
        ** The 'state' variable is described in more detail along with the
        ** descriptions of the values it may take - PAGER_UNLOCK etc. Many of the
        ** other variables in this block are described in the comment directly
        ** above this class definition.
        */
        public byte state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
        public bool dbModified; /* True if there are any changes to the Db */
        public bool needSync; /* True if an fsync() is needed on the journal */
        public bool journalStarted; /* True if header of journal is synced */
        public bool changeCountDone; /* Set after incrementing the change-counter */
        public int setMaster; /* True if a m-j name has been written to jrnl */
        public bool doNotSync; /* Boolean. While true, do not spill the cache */
        public bool dbSizeValid; /* Set when dbSize is correct */
        public byte subjInMemory; /* True to use in-memory sub-journals */
        public uint dbSize; /* Number of pages in the database */
        public uint dbOrigSize; /* dbSize before the current transaction */
        public uint dbFileSize; /* Number of pages in the database file */
        public int errCode; /* One of several kinds of errors */
        public int nRec; /* Pages journalled since last j-header written */
        public uint cksumInit; /* Quasi-random value added to every checksum */
        public uint nSubRec; /* Number of records written to sub-journal */
        public Bitvec pInJournal; /* One bit for each page in the database file */
        public sqlite3_file fd; /* File descriptor for database */
        public sqlite3_file jfd; /* File descriptor for main journal */
        public sqlite3_file sjfd; /* File descriptor for sub-journal */
        public long journalOff; /* Current write offset in the journal file */
        public long journalHdr; /* Byte offset to previous journal header */
        public PagerSavepoint[] aSavepoint; /* Array of active savepoints */
        public int nSavepoint; /* Number of elements in aSavepoint[] */
        public byte[] dbFileVers = new byte[16]; /* Changes whenever database file changes */
        public uint sectorSize; /* Assumed sector size during rollback */

        public ushort nExtra; /* Add this many bytes to each in-memory page */
        public short nReserve; /* Number of unused bytes at end of each page */
        public uint vfsFlags; /* Flags for sqlite3_vfs.xOpen() */
        public int pageSize; /* Number of bytes in a page */
        public uint mxPgno; /* Maximum allowed size of the database */
        public string zFilename; /* Name of the database file */
        public string zJournal; /* Name of the journal file */
        public dxBusyHandler xBusyHandler; /* Function to call when busy */
        public object pBusyHandlerArg; /* Context argument for xBusyHandler */
#if SQLITE_TEST || DEBUG
        public int nHit, nMiss; /* Cache hits and missing */
        public int nRead, nWrite; /* Database pages read/written */
#else
      public int nHit;
#endif
        public dxReiniter xReiniter; //(DbPage*,int);/* Call this routine when reloading pages */
#if SQLITE_HAS_CODEC
void *(*xCodec)(void*,void*,uint,int); /* Routine for en/decoding data */
void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
void (*xCodecFree)(void*);             /* Destructor for the codec */
void *pCodec;               /* First argument to xCodec... methods */
#endif
        public byte[] pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
        public long journalSizeLimit; /* Size limit for persistent journal files */
        public PCache pPCache; /* Pointer to page cache object */
        public sqlite3_backup pBackup; /* Pointer to list of ongoing backup processes */
    };
}